package com.ks3.demo.main;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.ksyun.ks3.exception.Ks3ClientException;
import com.ksyun.ks3.exception.Ks3ServiceException;
import com.ksyun.ks3.model.PartETag;
import com.ksyun.ks3.model.result.CompleteMultipartUploadResult;
import com.ksyun.ks3.model.result.InitiateMultipartUploadResult;
import com.ksyun.ks3.model.result.UploadPartResult;
import com.ksyun.ks3.services.Ks3Client;
import com.ksyun.ks3.services.handler.CompleteMultipartUploadResponseHandler;
import com.ksyun.ks3.services.handler.InitiateMultipartUploadResponseHandler;
import com.ksyun.ks3.services.handler.UploadPartResponseHandler;
import com.ksyun.ks3.services.request.CompleteMultipartUploadRequest;
import com.ksyun.ks3.services.request.InitiateMultipartUploadRequest;
import com.ksyun.ks3.services.request.UploadPartRequest;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class MultipartUploadExample {
    final private String TAG = "MultiUploadExample";
    private String bucketName;
    private String key;
    private File file;
    private long partSize = 5 * 1024 * 1024;
    private String uploadId;
    private Ks3Client client;
    final static private int STATE_UPLOAD_INIT = 0;
    final static private int STATE_UPLOAD_NEXT = 1;
    final static private int STATE_UPLOAD_COMPLETE = 2;
    final static private int STATE_UPLOAD_FAILED = 3;
    final private List<PartETag> uploadedParts = new ArrayList<>();
    UploadPartRequestFactory localUploadPartRequestFactory = null;

    private void create(Ks3Client client, String bucketName, String key, File file, long partSize) {
        this.client = client;
        this.bucketName = bucketName;
        this.key = key;
        this.file = file;
        this.partSize = partSize;
    }

    public MultipartUploadExample(Ks3Client client, String bucketName, String key, File file) {
        create(client, bucketName, key, file, partSize);
    }

    public MultipartUploadExample(Ks3Client client, String bucketName, String key, File file, long partSize) {
        create(client, bucketName, key, file, partSize);
    }

    private final UploadHandler handler = new UploadHandler();

    class UploadHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case STATE_UPLOAD_INIT:
                    initUpload();
                    break;
                case STATE_UPLOAD_NEXT:
                    uploadPart();
                    break;
                case STATE_UPLOAD_COMPLETE:
                    completeUpload();
                    break;
                case STATE_UPLOAD_FAILED:
                    Log.e(TAG, "upload failed");
                default:
                    break;
            }
        }
    }

    public void upload() {
        handler.sendEmptyMessage(STATE_UPLOAD_INIT);
    }

    private void initUpload() {
        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key);
        client.initiateMultipartUpload(request, new InitiateMultipartUploadResponseHandler() {
            @Override
            public void onSuccess(InitiateMultipartUploadRequest request, InitiateMultipartUploadResult result) {
                uploadId = result.getUploadId();
                localUploadPartRequestFactory = new UploadPartRequestFactory(bucketName, key, uploadId, file, partSize);
                Log.i(TAG, "init multipart upload success, uploadId=" + uploadId);
                handler.sendEmptyMessage(STATE_UPLOAD_NEXT);
            }

            @Override
            public void onFailure(InitiateMultipartUploadRequest request, Ks3ClientException clientException, Ks3ServiceException serviceException) {
                if (clientException != null) {
                    Log.e(TAG, "init multipart upload fail, clientException=" + clientException.getMessage());
                }
                if (serviceException != null) {
                    Log.e(TAG, "init multipart upload fail, serviceException=" + serviceException.getMessage());
                }
                handler.sendEmptyMessage(STATE_UPLOAD_FAILED);
            }
        });
    }

    private void uploadPart() {
        if (localUploadPartRequestFactory.hasMoreRequests()) {
            UploadPartRequest request = localUploadPartRequestFactory.getNextUploadPartRequest();
            client.uploadPart(request, new UploadPartResponseHandler() {
                @Override
                public void onSuccess(UploadPartRequest request, UploadPartResult result) {
                    PartETag partETag = result.getPartETag();
                    partETag.setPartNumber(request.getPartNumber());
                    uploadedParts.add(partETag);
                    Log.i(TAG, "upload part success, partNumber=" + partETag.getPartNumber() + ", eTag=" + partETag.geteTag());
                    handler.sendEmptyMessage(STATE_UPLOAD_NEXT);
                }

                @Override
                public void onTaskProgress(double progress) {
                }

                @Override
                public void onFailure(UploadPartRequest request, Ks3ClientException clientException, Ks3ServiceException serviceException) {
                    if (clientException != null) {
                        Log.e(TAG, "upload part fail, clientException=" + clientException.getMessage());
                    }
                    if (serviceException != null) {
                        Log.e(TAG, "upload part fail, serviceException=" + serviceException.getMessage());
                    }
                    handler.sendEmptyMessage(STATE_UPLOAD_FAILED);
                }
            });
        } else {
            // 发送完成消息
            handler.sendEmptyMessage(STATE_UPLOAD_COMPLETE);
        }
    }

    private void completeUpload() {
        CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(bucketName, key, uploadId, uploadedParts);
        client.completeMultipartUpload(request, new CompleteMultipartUploadResponseHandler() {
            @Override
            public void onSuccess(CompleteMultipartUploadRequest request, CompleteMultipartUploadResult result) {
                Log.i(TAG, "complete multipart upload success, status code=" + result.getStatusCode());
            }

            @Override
            public void onFailure(CompleteMultipartUploadRequest request, Ks3ClientException clientException, Ks3ServiceException serviceException) {
                if (clientException != null) {
                    Log.e(TAG, "complete multipart upload fail, clientException=" + clientException.getMessage());
                }
                if (serviceException != null) {
                    Log.e(TAG, "complete multipart upload fail, serviceException=" + serviceException.getMessage());
                }
                handler.sendEmptyMessage(STATE_UPLOAD_FAILED);
            }
        });
    }
}
